import { VNode } from "./VNode.js";
import { UIEventHandler } from "./ElemEventHandler.js";

function Renderer(page, document) {
    this.page = page;
    this.document = document;
}

Renderer.prototype.mount = function (nodeToMount, vnode) {
    var node = this.createNode(vnode);
    nodeToMount.appendChild(node);
};

Renderer.prototype.createNode = function (vnode) {

    var childrenElem = [];
    vnode.children.forEach((childVNode)=>{
        childrenElem.push(this.createNode(childVNode));
    });

    if (vnode.type === VNode.Type.Element) {
        if (! vnode.tag in this.vnodeCreator) {
            console.warn("create node, unknown tag '" + vnode.tag +"'");
            return null;
        }
        var elem = this.vnodeCreator[vnode.tag].call(this, vnode);
        childrenElem.forEach(function (childElem) {
            if (childElem) {
                elem.appendChild(childElem);
            }
        });
        return elem;
    }
    else if (vnode.type === VNode.Type.Text) {
        console.assert(childrenElem.length === 0);
        return document.createTextNode(vnode.text);
    }
    else {
        return null;
    }
};

Renderer.prototype.addEventHandler = function(elem, eventName, exp) {
    if (!elem || !eventName || !exp) {
        return;
    }

    let allowBubble = eventName.startsWith('bind');
    eventName = eventName.replace(/^(bind|catch):?/, '');

    new UIEventHandler(this.page, elem, eventName, exp, !allowBubble);
};

Renderer.prototype.createElementWithTag = function(vnode, tag) {
    var elem = this.document.createElement(tag);

    Object.keys(vnode.attrs).forEach(function (name) {
        elem.setAttribute(name, vnode.attrs[name]);
    });

    if (vnode.attrs.events) {
        Object.keys(vnode.attrs.events).forEach((eventName) => {
            this.addEventHandler(elem, eventName, vnode.attrs.events[eventName]);
        });
    }

    return elem;
};

Renderer.prototype.vnodeCreator = {
    'view': function (vnode) {
        return this.createElementWithTag(vnode, 'div');
    },
    'button': function (vnode) {
        return this.createElementWithTag(vnode, 'button');
    },
    'block': function (vnode) {
        return this.createElementWithTag(vnode, 'div');
    },
    'text': function (vnode) {
        return this.createElementWithTag(vnode, 'p');
    },
    'image': function (vnode) {
        return this.createElementWithTag(vnode, 'image');
    },
    'View': function (vnode) {
        return this.createElementWithTag(vnode, 'user-view');
    },
};

export function mountVNodeToBody(page, node, root) {
    var r = new Renderer(page, document);
    r.mount(node, root);
}
